import Cache from "./Cache";
import CacheObj from "./CacheObj";

export default abstract class AbstractCache<K, V> implements Cache<K, V> {
    public cacheMap: Map<K, CacheObj<K, V>>;
    /**
     * 返回缓存容量，{@code 0}表示无大小限制
     */
    protected capacityNum: number;
    /**
     * 缓存失效时长， {@code 0} 表示无限制，单位毫秒
     */
    protected timeoutArg: number;

    /**
     * 每个对象是否有单独的失效时长，用于决定清理过期对象是否有必要。
     */
    protected existCustomTimeout: boolean;

    /**
     * 命中数，即命中缓存计数
     */
    protected hitCount: number = 0;
    /**
     * 丢失数，即未命中缓存计数
     */
    protected missCount: number = 0;

    constructor(capacityNum: number, timeoutArg: number, existCustomTimeout: boolean) {
        this.capacityNum = capacityNum;
        this.timeoutArg = timeoutArg;
        this.existCustomTimeout = existCustomTimeout;
        this.cacheMap = new Map<K, CacheObj<K, V>>();
    }

    capacity(): number {
        return this.capacityNum;
    }

    clear(): void {
        this.cacheMap.clear();
    }

    containsKey(key: K): boolean {
        return false;
    }
    get(key: K): V | null;
    get(key: K, supplier?: Function): V | null {
        const co: CacheObj<K, V> | undefined = this.cacheMap.get(key);
        if (!co) {
            this.missCount++
            return supplier && supplier()
        } else if (!co.isExpired()) {
            this.hitCount++
            return co.get(true)
        }
        this.remove(key)
        return null
    }

    isEmpty(): boolean {
        return this.cacheMap.size === 0;
    }

    isFull(): boolean {
        return this.capacityNum > 0 && this.cacheMap.size >= this.capacityNum;
    }

    prune(): number {
        return this.pruneCache();
    }

    put(key: K, object: V): void;
    put(key: K, object: V, timeout: number): void;
    put(key: K, object: V, timeout?: number): void {
        timeout = timeout || this.timeoutArg
        let co: CacheObj<K, V> = new CacheObj<K, V>(key, object, timeout);
        if (timeout != 0) {
            this.existCustomTimeout = true;
        }
        if (this.isFull()) {
            this.pruneCache();
        }
        this.cacheMap.set(key, co);
    }

    remove(key: K): void;
    remove(key:K,withMissCount?:boolean):void {
        withMissCount = withMissCount || true
        this.removeWithoutLock(key, withMissCount);
    }
    private removeWithoutLock(key: K, withMissCount: boolean): boolean {
        const result = this.cacheMap.delete(key);
        if (withMissCount) {
            // 在丢失计数有效的情况下，移除一般为get时的超时操作，此处应该丢失数+1
            this.missCount--
        }
        return result;
    }

    size(): number {
        return this.cacheMap.size;
    }

    timeout(): number {
        return this.timeoutArg;
    }

    /**
     * 清理实现<br>
     * 子类实现此方法时无需加锁
     *
     * @return 清理数
     */
    protected abstract pruneCache(): number;
}